package spring.webmvc;

import spring.context.ConfigurableWebApplicationContext;
import spring.context.WebApplicationContext;
import spring.context.servlet.SimpleWebApplicationContext;

import javax.servlet.ServletContext;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ContextLoader {

    public static final String ANNOTATION_NAME = "$_ANNOTATION_NAME_$";

    private static final Map<ClassLoader, WebApplicationContext> currentContextPerThread =
            new ConcurrentHashMap<>(1);
    private static volatile WebApplicationContext currentContext;
    private ConfigurableWebApplicationContext context;

    public static WebApplicationContext getCurrentWebApplicationContext() {
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if (ccl != null) {
            WebApplicationContext ccpt = currentContextPerThread.get(ccl);
            if (ccpt != null) {
                return ccpt;
            }
        }
        return currentContext;
    }

    public void initWebApplicationContext(ServletContext servletContext) {

        this.context = createWebApplicationContext(servletContext);

        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if (ccl == ContextLoader.class.getClassLoader()) {
            currentContext = this.context;
        } else if (ccl != null) {
            currentContextPerThread.put(ccl, this.context);
        }
    }

    public ConfigurableWebApplicationContext createWebApplicationContext(ServletContext servletContext) {
        ConfigurableWebApplicationContext context = new SimpleWebApplicationContext(servletContext);
        context.initialApplicationContext();
        return context;
    }

    public void closeWebApplicationContext(ServletContext servletContext) {
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if (ccl == ContextLoader.class.getClassLoader()) {
            currentContext = null;
        } else if (ccl != null) {
            currentContextPerThread.remove(ccl);
        }
        servletContext.removeAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        this.context = null;
    }
}
